# 将图片和标注数据按比例切分为 训练集和测试集
import shutil
import random
import os
import argparse


# 检查文件夹是否存在，如果不存在则创建它
# 目录创建函数
def mkdir(path):
    if not os.path.exists(path):
        os.makedirs(path)


def main(image_dir, txt_dir, save_dir):
    # 创建文件夹
    # 创建用于保存分割后数据集的主目录save_dir。
    mkdir(save_dir)
    images_dir = os.path.join(save_dir, 'images')
    labels_dir = os.path.join(save_dir, 'labels')

    img_train_path = os.path.join(images_dir, 'train')
    img_test_path = os.path.join(images_dir, 'test')
    img_val_path = os.path.join(images_dir, 'val')

    label_train_path = os.path.join(labels_dir, 'train')
    label_test_path = os.path.join(labels_dir, 'test')
    label_val_path = os.path.join(labels_dir, 'val')

    mkdir(images_dir)
    mkdir(labels_dir)
    mkdir(img_train_path)
    mkdir(img_test_path)
    mkdir(img_val_path)
    mkdir(label_train_path)
    mkdir(label_test_path)
    mkdir(label_val_path)

    # 数据集划分比例，训练集75%，验证集15%，测试集15%，按需修改
    train_percent = 0.8
    val_percent = 0.1
    test_percent = 0.1

    # 获取所有文件并计算数量
    total_txt = os.listdir(txt_dir)
    num_txt = len(total_txt)
    list_all_txt = range(num_txt)  # 范围 range(0, num)

    # 计算各个集的数据数量
    num_train = int(num_txt * train_percent)
    num_val = int(num_txt * val_percent)
    num_test = num_txt - num_train - num_val

    # 随机抽样生成训练集和验证集
    # random.sample 函数从 list_all_txt（包含所有文件的索引范围）中随机抽取 num_train 个索引，生成训练集。
    # random.sample 函数确保从中选择的元素是唯一的，因此不会有重复的文件索引。
    train = random.sample(list_all_txt, num_train)

    # 生成验证集和测试集的候选集合
    # 在全部数据集中取出train
    val_test = [i for i in list_all_txt if not i in train]

    # 随机抽样生成验证集
    # 再从val_test取出num_val个元素，val_test剩下的元素就是test
    val = random.sample(val_test, num_val)

    # 打印训练集、验证集和测试集的文件数量。
    print("训练集数目：{}, 验证集数目：{},测试集数目：{}".format(len(train), len(val), len(val_test) - len(val)))
    for i in list_all_txt:
        name = total_txt[i][:-4]

        # image_dir 是一个字符串变量，包含图像文件所在目录的路径。
        srcImage = os.path.join(image_dir, name + '.jpg')
        srcLabel = os.path.join(txt_dir, name + '.txt')

        if i in train:
            dst_train_Image = os.path.join(img_train_path, name + '.jpg')
            dst_train_Label = os.path.join(label_train_path, name + '.txt')

            # srcImage这是源文件的路径，表示要被复制的文件。
            # dst_train_Image这是目标文件的路径，表示要复制到的新文件
            shutil.copyfile(srcImage, dst_train_Image)
            shutil.copyfile(srcLabel, dst_train_Label)
        elif i in val:
            dst_val_Image = os.path.join(img_val_path, name + '.jpg')
            dst_val_Label = os.path.join(label_val_path, name + '.txt')
            shutil.copyfile(srcImage, dst_val_Image)
            shutil.copyfile(srcLabel, dst_val_Label)
        else:
            dst_test_Image = os.path.join(img_test_path, name + '.jpg')
            dst_test_Label = os.path.join(label_test_path, name + '.txt')
            shutil.copyfile(srcImage, dst_test_Image)
            shutil.copyfile(srcLabel, dst_test_Label)


if __name__ == '__main__':

    """"
    python split_datasets.py --image-dir my_datasets/color_rings/imgs --txt-dir my_datasets/color_rings/txts --save-dir my_datasets/color_rings/train_data
    """
    # 这行代码创建一个ArgumentParser 对象，用于处理命令行参数。description 参数提供了一个描述，说明这个脚本的用途。
    parser = argparse.ArgumentParser(description='split datasets to train,val,test params')

    parser.add_argument('--image-dir', type=str, default=r'C:\Al\Software\AI_Model\Project\yolov5\yolov5\my_data\dataset_20250114_163651_yolo\dataset\images',
                        help='image path dir')

    parser.add_argument('--txt-dir', type=str, default=r'C:\Al\Software\AI_Model\Project\yolov5\yolov5\my_data\dataset_20250114_163651_yolo\dataset\labels',
                        help='txt path dir')

    parser.add_argument('--save-dir', default=r'C:\Al\Software\AI_Model\Project\yolov5\yolov5\my_data\train_data\train_pretreatment', type=str,
                        help='save dir')

    args = parser.parse_args()

    image_dir = args.image_dir

    txt_dir = args.txt_dir

    save_dir = args.save_dir

    main(image_dir, txt_dir, save_dir)
